package com.libnetwork.httpservice.calladapter

import com.libnetwork.HttpException
import com.libnetwork.Network
import com.libnetwork.httpservice.HttpService
import io.reactivex.rxjava3.core.BackpressureStrategy
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.core.Scheduler
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.plugins.RxJavaPlugins
import retrofit2.Call
import retrofit2.CallAdapter
import java.lang.reflect.Type
import java.net.SocketTimeoutException
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger

class RxJava3CallAdapter<R : Any>(
    private val responseType: Type,
    private val scheduler: Scheduler?,
    private val isAsync: Boolean,
    private val isResult: Boolean,
    private val isBody: Boolean,
    private val isFlowable: Boolean,
    private val isSingle: Boolean,
    private val isMaybe: Boolean,
    private val isCompletable: Boolean,
) : CallAdapter<R, Any> {
    override fun responseType(): Type {
        return responseType
    }

    override fun adapt(call: Call<R>): Any {
        val responseObservable =
            if (isAsync) CallEnqueueObservable(call) else CallExecuteObservable(
                call
            )

        var observable: Observable<*>
        observable = if (isResult) {
            ResultObservable(responseObservable)
        } else if (isBody) {
            BodyObservable(responseObservable)
        } else {
            responseObservable
        }

        if (scheduler != null) {
            observable = observable.subscribeOn(scheduler)
        }

        observable = HttpService.instance.retry(observable)

        if (isFlowable) {
            return observable.toFlowable(BackpressureStrategy.LATEST)
        }
        if (isSingle) {
            return observable.singleOrError()
        }
        if (isMaybe) {
            return observable.singleElement()
        }
        return if (isCompletable) {
            observable.ignoreElements()
        } else RxJavaPlugins.onAssembly(observable)
    }
}